/***********************************************************************************************************************
 * ############################################# Application AdewebLite #############################################
 * AdewebLite Android est une application permettant de consulter des emplois du temps fournis par l'université UHP
 * avec ou sans connexion internet (informations gardées en mémoire à chaque synchronisation). Et utilisant la web
 * API ADE pour collecter les données.
 * @author Andrianjafintrimo Victor, Zanette Sébastien
 * 
 * Basée sur l'application du même nom, utilisant le flux RSS (données à traiter), de :
 * @author Schnell Michaël, Zanette Sébastien
 * **********************************************************************************************************************
 */
package ade.prime.activity.adapter;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import ade.prime.activity.R;
import ade.prime.model.AdeWebOptions;
import ade.prime.model.Lesson;
import ade.prime.model.Lessons;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SimpleExpandableListAdapter;
import android.widget.TextView;

/**
 * Défini la structure de la vue de la liste de cours d'un emploi du temps.
 * Chaque ligne affiche le nom du cours, l'heure du cours, et la salle.
 * @author Seb
 */
public class ListLessonAdapter extends SimpleExpandableListAdapter {
	
	@SuppressWarnings("unused")
	private static final String TAG = ListLessonAdapter.class.getSimpleName() ;
	
	private static final String TITLE = "TITLE" ; //$NON-NLS-1$
	private static final String TIME  = "TIME"  ; //$NON-NLS-1$
	private static final String ROOM  = "ROOM"  ; //$NON-NLS-1$
	private static final String COLOR = "COLOR" ; //$NON-NLS-1$
	private static final String BIG_CHANGE = "BIG_CHANGE" ; //$NON-NLS-1$
	private static final String ID = "ID" ; //$NON-NLS-1$
	private static final String LESSON_ID = "LESSON_ID" ; //$NON-NLS-1$
	
	public static final String DATE_FORMAT_DAY = "EEEE dd MMMM" ; //$NON-NLS-1$
	
	public static final String DATE_FORMAT_WEEK_START = "ww (dd/MM - " ; //$NON-NLS-1$
	public static final String DATE_FORMAT_WEEK_END   = "dd/MM)" ; //$NON-NLS-1$
	
	public static final String DATE_FORMAT_MONTH = "MMMM yyyy" ; //$NON-NLS-1$
	
	protected boolean useColor ;
	
	protected List<Map<String, String>> groupData ;
	
	protected List<List<Map<String, String>>> childData ;
	
	protected ViewType viewType ;
	
	private Context context;
	
	/**
	 * {@inheritDoc}
	 */
	public ListLessonAdapter(Context context,
			List<Map<String, String>> groupData, int groupLayout,
			String[] groupFrom, int[] groupTo,
			List<List<Map<String, String>>> childData,
			int childLayout, String[] childFrom, int[] childTo,
			ViewType viewType) {
		super(context, groupData, groupLayout, groupFrom, groupTo, childData,
				childLayout, childFrom, childTo) ;
		this.groupData = groupData ;
		this.childData = childData ;
		this.viewType = viewType ;
		this.useColor = AdeWebOptions.useAdeWebColors(context) ;
		this.context = context;
	}// ListLessonAdapter(Context, List<? extends Map<String, ?>>, int, String[], int[], List<? extends List<? extends Map<String, ?>>>, int, String[], int[])

	public static ListLessonAdapter getInstance(Context context, Lessons lessons,
			ViewType type) {
		List<Map<String, String>> groupData = 
        		new ArrayList<Map<String, String>>() ;
        List<List<Map<String, String>>> childData = 
        		new ArrayList<List<Map<String, String>>>() ;
        if (lessons.size() > 0) {
        	switch(type) {
        	case DAILY:
        		buildDailySepartors(groupData, childData, lessons, context) ;
        		break ;
        	case WEEKLY:
        		buildWeeklySepartors(groupData, childData, lessons, context) ;
        		break ;
//        	case MONTHLY:
//        		buildMonthlySepartors(groupData, childData, lessons, context) ;
//        		break ;
        	}// switch
        }// if
		
		return new ListLessonAdapter(
				context,
                groupData,
                R.layout.lesson_item_list_header,
                new String[] { TITLE },
                new int[] { R.id.lesson_list_item_date },
                childData,
                R.layout.lesson_item_list_block,
                new String[] { TITLE, TIME, ROOM },
                new int[] { R.id.block_title, R.id.block_time, R.id.block_subtitle },
				type) ;
	}// getInstance(Context, Lessons, ViewType)
	
	public void setLessons(Lessons lessons, Context context) {
		this.groupData.clear() ;
		this.childData.clear() ;
        if (lessons.size() > 0) {
        	switch(this.viewType) {
        	case DAILY:
        		buildDailySepartors(this.groupData, this.childData, lessons, context) ;
        		break ;
        	case WEEKLY:
        		buildWeeklySepartors(this.groupData, this.childData, lessons, context) ;
        		break ;
//        	case MONTHLY:
//        		buildMonthlySepartors(this.groupData, this.childData, lessons, context) ;
//        		break ;
        	}// switch
        }// if
        this.notifyDataSetChanged() ;
	}// setLessons(Lessons)
	
	/**
	 * @param useColor the useColor to set
	 */
	public void setUseColor(boolean useColor) {
		this.useColor = useColor ;
	}
	
	public void updateLessonType(Lesson lesson) {
		String lessonId = Long.toString(lesson.getLessonId()) ;
		Iterator<List<Map<String, String>>> groupIter = this.childData.iterator() ;
		boolean found = false ;
		while (!found && groupIter.hasNext()) {
			List<Map<String, String>> groupChildren = groupIter.next() ;
			Iterator<Map<String, String>> childIter = groupChildren.iterator() ;
			while (!found && childIter.hasNext()) {
				Map<String, String> childValues = childIter.next() ;
				if (lessonId.equals(childValues.get(LESSON_ID))) {
					found = true ;
					childValues.put(TITLE, getTitle(lesson)) ;
					this.notifyDataSetChanged() ;
				}// if
			}// while
		}// while
	}// udpateLessonType(Lesson)
	
	public void removeLessonHistory(long removedLessonId) {
		String lessonId = Long.toString(removedLessonId) ;
		Iterator<List<Map<String, String>>> groupIter = this.childData.iterator() ;
		boolean found = false ;
		while (!found && groupIter.hasNext()) {
			List<Map<String, String>> groupChildren = groupIter.next() ;
			Iterator<Map<String, String>> childIter = groupChildren.iterator() ;
			while (!found && childIter.hasNext()) {
				Map<String, String> childValues = childIter.next() ;
				if (lessonId.equals(childValues.get(LESSON_ID))) {
					found = true ;
					childValues.put(BIG_CHANGE, Boolean.FALSE.toString()) ;
					this.notifyDataSetChanged() ;
				}// if
			}// while
		}// while
//		Log.d(TAG, "Lesson found: " + found) ;
	}// udpateLessonType(Lesson)
	
	/**
	 * {@inheritDoc}	
	 */
	@Override
	public long getChildId(int groupPosition, int childPosition) {
		@SuppressWarnings("unchecked")
		Map<String, String> childValues = 
				(Map<String, String>) this.getChild(groupPosition, childPosition) ;
		return Long.valueOf(childValues.get(ID)).longValue() ;
	}// getChildId(int, int)
	
	@Override
	public View getChildView(int groupPosition, int childPosition, 
			boolean isLastChild, View convertView, 
			ViewGroup parent) {
		View childView = super.getChildView(groupPosition, childPosition, 
				isLastChild, convertView, parent) ;
		this.setupView(childView, this.getChild(groupPosition, childPosition)) ;
		return childView ;
	}// getChildView(int, int, boolean, View, ViewGroup)
	
	
	@Override
	public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
		View groupView = super.getGroupView(groupPosition, isExpanded, convertView, parent) ;
		TextView titleView = (TextView) groupView.findViewById(R.id.lesson_list_item_date) ;
		titleView.setTextColor(AdeWebOptions.getTextColor(AdeWebOptions.getTheme(this.context)));
		return groupView ;
	}// getChildView(int, int, boolean, View, ViewGroup)
	
	private void setupView(View view, Object child) {
		@SuppressWarnings("unchecked")
		Map<String, String> childValues = (Map<String, String>) child ;
		boolean colorItem = this.useColor ;

//		TextView timeView  = (TextView) view.findViewById(R.id.block_time) ;
		TextView titleView = (TextView) view.findViewById(R.id.block_title) ;
		TextView roomView  = (TextView) view.findViewById(R.id.block_subtitle) ;

		int bgColor = Color.TRANSPARENT ;
		int textColor = Color.LTGRAY ;
		int textColor2 = Color.LTGRAY ;
		if (colorItem) {
			bgColor = Color.parseColor(childValues.get(COLOR)) ;
			textColor = Color.BLACK ;
			textColor2 = Color.BLACK ;
		}// if
		else {
			textColor2 = AdeWebOptions.getTextColorViewSchedule(AdeWebOptions.getTheme(this.context));
		}
		// Set background color
		view.setBackgroundColor(bgColor) ;
		// Change font color
		//si le thème choisi est blanc, le titre doit etre noir
		titleView.setTextColor(textColor2) ;
		roomView.setTextColor(textColor) ;

		// Hide/Show "big change" icon
		View icon = view.findViewById(R.id.change) ;
		String bigChange = childValues.get(BIG_CHANGE) ;
		if ((bigChange != null) && Boolean.valueOf(bigChange).equals(Boolean.TRUE)) {
			icon.setVisibility(View.VISIBLE) ;
		} else {
			icon.setVisibility(View.INVISIBLE) ;
		}// if
	}//setupView()

	@SuppressWarnings("null")
	private static void buildDailySepartors(List<Map<String, String>> groupData,
			List<List<Map<String, String>>> childData, Lessons lessons, Context context) {
		final SimpleDateFormat dateFormater = 
				new SimpleDateFormat(DATE_FORMAT_DAY, Locale.FRANCE) ;
		String currentDate = null ;
		List<Map<String, String>> children = null ;
		int id = 0 ;
		for(Lesson lesson : lessons) {
			String date = lesson.getTime() ;
			date = date.substring(0, date.indexOf(" ")) ; //$NON-NLS-1$
			if (!date.equals(currentDate)) {
				String formattedDate = dateFormater.format(lesson.getDate()) ;
				// Capitalize first letter
				formattedDate = String.format("%S%s", //$NON-NLS-1$
						formattedDate.substring(0, 1),
						formattedDate.substring(1)) ;
				currentDate = date ;
				Map<String, String> curGroupMap = new HashMap<String, String>() ;
				curGroupMap.put(TITLE, formattedDate) ;
				groupData.add(curGroupMap) ;
				
				children = new ArrayList<Map<String, String>>() ;
				childData.add(children) ;
			}// if
			Map<String, String> curChildMap = new HashMap<String, String>() ;
			children.add(curChildMap) ;
			curChildMap.put(TITLE, getTitle(lesson)) ;
			curChildMap.put(TIME, getTime(lesson, ViewType.DAILY)) ;
			curChildMap.put(ROOM, getRoom(lesson, context)) ;
			curChildMap.put(COLOR, lesson.getColor()) ;
			if (lesson.getHistory() != null) {
				curChildMap.put(BIG_CHANGE, Boolean.TRUE.toString()) ;
			}// if
			curChildMap.put(ID, Integer.toString(id)) ;
			curChildMap.put(LESSON_ID, Long.toString(lesson.getLessonId())) ;
			++id ;
		}// for
	}// buildDailySepartors(List<Map<String, String>>, List<List<Map<String, String>>>, Lessons, Context)

	private static void buildWeeklySepartors(List<Map<String, String>> groupData,
			List<List<Map<String, String>>> childData, Lessons lessons, Context context) {
		final SimpleDateFormat weekDateFormaterStart = 
				new SimpleDateFormat(DATE_FORMAT_WEEK_START, Locale.FRANCE) ;
		final SimpleDateFormat weekDateFormaterEnd = 
				new SimpleDateFormat(DATE_FORMAT_WEEK_END, Locale.FRANCE) ;
		final SimpleDateFormat dateFormater =
				new SimpleDateFormat("yyyy/MM/dd") ; //$NON-NLS-1$
		
		GregorianCalendar calendar = getCalendar(lessons.get(0)) ;
		Map<String, String> curGroupMap = new HashMap<String, String>() ;
		curGroupMap.put(TITLE, getWeekTitle(weekDateFormaterStart, weekDateFormaterEnd, 
				calendar, context)) ;
		groupData.add(curGroupMap) ;
		List<Map<String, String>> children = new ArrayList<Map<String, String>>() ;
		childData.add(children) ;
		int id = 0 ;
		String nextWeekStart = getNextWeekStart(dateFormater, calendar) ;
		for(Lesson lesson : lessons) {
			String date = lesson.getTime() ;
			date = date.substring(0, date.indexOf(" ")) ; //$NON-NLS-1$
			if (date.compareTo(nextWeekStart) >= 0) {
				calendar = getCalendar(lesson) ;
				curGroupMap = new HashMap<String, String>() ;
				curGroupMap.put(TITLE, getWeekTitle(weekDateFormaterStart,
						weekDateFormaterEnd, calendar, context)) ;
				groupData.add(curGroupMap) ;
				children = new ArrayList<Map<String, String>>() ;
				childData.add(children) ;
				nextWeekStart = getNextWeekStart(dateFormater, calendar) ;
			}// if
			Map<String, String> curChildMap = new HashMap<String, String>() ;
			children.add(curChildMap) ;
			curChildMap.put(TITLE, getTitle(lesson)) ;
			curChildMap.put(TIME, getTime(lesson, ViewType.WEEKLY)) ;
			curChildMap.put(ROOM, getRoom(lesson, context)) ;
			curChildMap.put(COLOR, lesson.getColor()) ;
			if (lesson.getHistory() != null) {
				curChildMap.put(BIG_CHANGE, Boolean.TRUE.toString()) ;
			}// if
			curChildMap.put(ID, Integer.toString(id)) ;
			curChildMap.put(LESSON_ID, Long.toString(lesson.getLessonId())) ;
			++id ;
		}// for
	}// buildWeeklySepartors(List<Map<String, String>>, List<List<Map<String, String>>>, Lessons, Context)

//	@SuppressWarnings("null")
//	private static void buildMonthlySepartors(List<Map<String, String>> groupData,
//			List<List<Map<String, String>>> childData, Lessons lessons, Context context) {
//		final SimpleDateFormat dateFormater = 
//				new SimpleDateFormat(DATE_FORMAT_MONTH, Locale.FRANCE) ;
//		String currentDate = null ;
//		List<Map<String, String>> children = null ;
//		int id = 0 ;
//		for(Lesson lesson : lessons) {
//			String date = lesson.getTime() ;
//			date = date.substring(0, date.indexOf(" ")-3) ; //$NON-NLS-1$
//			if (!date.equals(currentDate)) {
//				String formattedDate = dateFormater.format(lesson.getDate()) ;
//				// Capitalize first letter
//				formattedDate = String.format("%s%s", //$NON-NLS-1$
//						formattedDate.substring(0, 1).toUpperCase(),
//						formattedDate.substring(1)) ;
//				currentDate = date ;
//				Map<String, String> curGroupMap = new HashMap<String, String>() ;
//				curGroupMap.put(TITLE, formattedDate) ;
//				groupData.add(curGroupMap) ;
//				
//				children = new ArrayList<Map<String, String>>() ;
//				childData.add(children) ;
//			}// if
//			Map<String, String> curChildMap = new HashMap<String, String>() ;
//			children.add(curChildMap) ;
//			curChildMap.put(TITLE, getTitle(lesson)) ;
//			curChildMap.put(TIME, getTime(lesson, ViewType.MONTHLY)) ;
//			curChildMap.put(ROOM, getRoom(lesson, context)) ;
//			curChildMap.put(COLOR, lesson.getColor()) ;
//			if (lesson.getChange() == Lesson.BIG_CHANGE) {
//				curChildMap.put(BIG_CHANGE, Boolean.TRUE.toString()) ;
//			}// if
//			curChildMap.put(ID, Integer.toString(id)) ;
//			curChildMap.put(LESSON_ID, Long.toString(lesson.getLessonId())) ;
//			++id ;
//		}// for
//	}// buildMonthlySepartors(List<Map<String, String>>, List<List<Map<String, String>>>, Lessons, Context)
	
	private static String getTitle(Lesson lesson) {
		StringBuilder titleBuilder = new StringBuilder(lesson.getTitle()) ;
		switch (lesson.getType()) {
		case IMPORTANT:
			titleBuilder.append(" (important)") ; //$NON-NLS-1$
			break ;
		case EXAM:
			titleBuilder.append(" (partiel)") ; //$NON-NLS-1$
			break ;
		default:
		}// switch
		return titleBuilder.toString() ;
	}// getTitle(Lesson)
	
	private static String getTime(Lesson lesson, ViewType viewType) {
		StringBuilder timeBuilder = new StringBuilder() ;
		if (!viewType.equals(ViewType.DAILY)) {
			timeBuilder.append(getFormattedDay(lesson)) ;
			timeBuilder.append('\n') ;
		}// if
		String lessonTime = lesson.getTime() ; 
		lessonTime = lessonTime.substring(lessonTime.indexOf(' ') + 1) ;
		// TODO Remove hard-coded messages
		timeBuilder.append(lessonTime.replace("- ", "\n\t-\n")) ; //$NON-NLS-1$ //$NON-NLS-2$
		return timeBuilder.toString() ;
	}// getTime(Lesson)
	
	protected static String getFormattedDay(Lesson lesson) {
		String date = lesson.getTime() ;
		date = date.substring(0, date.indexOf(" ")) ; //$NON-NLS-1$
		String[] dateParts = date.split("/") ; //$NON-NLS-1$
		// Set the date to the date of the first lesson
		int year =  Integer.valueOf(dateParts[0]).intValue() ;
		int month = Integer.valueOf(dateParts[1]).intValue() ;
		int day =   Integer.valueOf(dateParts[2]).intValue() ;
		// First month is numbered 0 (not 1), therefore the -1
		GregorianCalendar calendar = new GregorianCalendar(year, month-1, day) ;
		SimpleDateFormat dayFormatter = new SimpleDateFormat(
				"EEEE ", Locale.FRANCE) ; //$NON-NLS-1$
		String formattedDay = dayFormatter.format(calendar.getTime()) ;
		return String.format("%C%s",  //$NON-NLS-1$
				Character.valueOf(formattedDay.charAt(0)),
				formattedDay.substring(1)) ;
	}// getFormattedDay()
	
	private static String getRoom(Lesson lesson, Context context) {
		String room = lesson.getRoom() ;
		if ((room == null) || isEmpty(room)) {
			room = context.getResources().getString(R.string.Lesson_room_unknown) ;
		}// if
		return room ;
	}// getRoom(Lesson)
	
	protected static boolean isEmpty(String s) {
		return (s.length() == 0) ;
	}// isEmpty(String)
	
	private static GregorianCalendar getCalendar(Lesson lesson) {
		String date = lesson.getTime() ;
		date = date.substring(0, date.indexOf(" ")) ; //$NON-NLS-1$
		String[] dateParts = date.split("/") ; //$NON-NLS-1$
		// Set the date to the date of the first lesson
		int year =  Integer.valueOf(dateParts[0]).intValue() ;
		int month = Integer.valueOf(dateParts[1]).intValue() ;
		int day =   Integer.valueOf(dateParts[2]).intValue() ;
		// First month is numbered 0 (not 1), therefore the -1
		GregorianCalendar calendar = new GregorianCalendar(year, month-1, day) ;
		// Set the day to the first previous monday
//		Log.d(TAG, "Monday: " + Calendar.MONDAY) ;
//		Log.d(TAG, "Day before: " + calendar.get(Calendar.DAY_OF_WEEK)
//				+ " -- " + calendar.getTime()) ;
		while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
			calendar.add(Calendar.DAY_OF_WEEK, -1) ;
//			Log.d(TAG, "  -1 => " + calendar.get(Calendar.DAY_OF_WEEK)
//					+ " -- " + calendar.getTime()) ;
		}// while
//		Log.d(TAG, "Day after: " + calendar.get(Calendar.DAY_OF_WEEK)
//				+ " -- " + calendar.getTime()) ;
		return calendar ;
	}// getCalendar() ;
	
	private static String getNextWeekStart(SimpleDateFormat dateFormater,
			GregorianCalendar calendar) {
		// Set the day to the next monday
		while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
			calendar.add(Calendar.DAY_OF_WEEK, 1) ;
		}// while
		return dateFormater.format(calendar.getTime()) ;
	}// getNextWeekStart(Calendar)
	
	private static String getWeekTitle(SimpleDateFormat dateFormaterStart,
			SimpleDateFormat dateFormaterEnd, Calendar calendar,
			Context context) {
		Date monday = calendar.getTime() ;
		calendar.add(Calendar.DAY_OF_YEAR, 6) ;
		Date nextMonday = calendar.getTime() ;
		return String.format("%s %s%s",  //$NON-NLS-1$
				context.getResources().getString(R.string.ViewSchedule_week),
				dateFormaterStart.format(monday),
				dateFormaterEnd.format(nextMonday)) ;
	}// getWeekTitle(SimpleDateFormat, Calendar)
	
	public static enum ViewType {
		DAILY, WEEKLY/*, MONTHLY*/ ;
	}// enum ViewType
	
}// class ListLessonAdapter